package Service;

import java.net.URL;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Set;
import java.util.StringTokenizer;

import models.Flag;
import models.Group;
import models.taggedParams;
import models.untaggedParams;

import org.apache.axis.types.IDRefs;

import edu.sdsc.nbcr.opal.AppConfigInputType;
import edu.sdsc.nbcr.opal.AppConfigType;
import edu.sdsc.nbcr.opal.AppMetadataType;
import edu.sdsc.nbcr.opal.AppServiceLocator;
import edu.sdsc.nbcr.opal.AppServicePortType;
import edu.sdsc.nbcr.opal.FlagsArrayType;
import edu.sdsc.nbcr.opal.FlagsType;
import edu.sdsc.nbcr.opal.GroupsArrayType;
import edu.sdsc.nbcr.opal.GroupsType;
import edu.sdsc.nbcr.opal.ParamsArrayType;
import edu.sdsc.nbcr.opal.ParamsType;



public class GetServerInfo {

	
	private ArrayList<Flag> flag_set = new ArrayList<Flag> ();
	private ArrayList<taggedParams> tagged_set = new ArrayList<taggedParams>();
	private ArrayList<untaggedParams> untagged_set = new ArrayList<untaggedParams>();
	
	//arraylist of groups
	private ArrayList<Group> group_set = new ArrayList<Group>();
	//the group=>unknown group
	private Group unknownGroup = new Group();
	
	private String appname;
	
	private String usage;
	
	private String[] infos;
	
	private String separator;	
	
	private Set<String> file_set = new HashSet<String> ();
	
	private boolean basic;
	
	public GetServerInfo(){
	}
	
	//get servicemetadata!!!!!!!!!!!!!!!!!!!!!!!!
	public void Config(String opal_url){
		
		  //String opal_url = "http://ws.nbcr.net/opal2/services/Pdb2pqrOpalService";
		  String url = opal_url;
		
		  AppServiceLocator asl = new AppServiceLocator();
		  //AppServicePortType appServicePort;
		  //AppMetadataType amt;
			boolean has_tagged = true;
			boolean has_untagged = true;
			boolean has_flags = true;
			boolean has_groups = true;
			
			
			
			try {
				//appServicePort = asl.getAppServicePort(new java.net.URL(opal_url));
				
				//amt = appServicePort.getAppMetadata(new AppMetadataInputType());
				
	            AppServicePortType appServicePort = asl.getAppServicePort(new URL(opal_url));
	    	    AppConfigType act = appServicePort.getAppConfig(new AppConfigInputType());
	    	    AppMetadataType amt = act.getMetadata();
				//get app name, usage, app infos. 
				appname = amt.getAppName();
				
				usage = amt.getUsage();
				//System.out.println("usage: "+ usage);
				
				infos = amt.getInfo();
				
				ParamsType [] paramType = null;
				ArrayList args = new ArrayList();
				
				//check if flag, tagged untagged group are true.
				try { 
					ParamsType[] untaggeds = amt.getTypes().getTaggedParams().getParam();
					int length = untaggeds.length;
				} catch (NullPointerException npe) {
					has_tagged = false;
				}
				
				try { 
					ParamsType[] taggeds =  amt.getTypes().getUntaggedParams().getParam();
					int length = taggeds.length;
				} catch (NullPointerException npe) {
					has_untagged = false;
				}
				
				try {
					FlagsType[] flags =  amt.getTypes().getFlags().getFlag();
					int length = flags.length;
				} catch (NullPointerException npe) {
					has_flags = false;
				}
				
				try {
					unknownGroup.setUseful(false);
					GroupsType[] groups = amt.getTypes().getGroups().getGroup();
					int length = groups.length;
				} catch (NullPointerException npe) {
					has_groups = false;
				}
				
				if (has_tagged == false && has_untagged == false && has_flags == false) {
					basic = true;
				} 
				else {
					basic = false;
					if(has_groups != false){
						//get all groups
						GroupsArrayType groupArrayType = amt.getTypes().getGroups();
								
								//get all groups
								GroupsType[] groups = groupArrayType.getGroup();
								
								
								//loop through groups
								for(int i= 0; i < groups.length; i++){
									String groupName = groups[i].getName().toString();
									IDRefs groupElement = groups[i].getElements();
									String groupDec = groups[i].getTextDesc();//get description
									
									boolean groupReq;//get required?
									try{
										groupReq = groups[i].getRequired();
									}catch(NullPointerException e){
										groupReq = false;
									}
									
									boolean groupExc;//get exclusive?
									try{
										groupExc = groups[i].getExclusive();
									}catch(NullPointerException e){
										groupExc = false;
									}
								
									//add infos into this group
									Group thisgroup = new Group();
									thisgroup.setName(groupName);
							        StringTokenizer tokenizer = new StringTokenizer(groupElement.toString());
					                ArrayList<String> ids = new ArrayList<String>();
							        while ( tokenizer.hasMoreTokens() ){
							        	String id = tokenizer.nextToken();
						                ids.add(id);
							        }
							        thisgroup.setIds(ids);
									thisgroup.setText(groupDec);
									thisgroup.setRequired(groupReq);
									thisgroup.setExclusive(groupExc);
									group_set.add(thisgroup);
								}
								
					}//end of group if
					
					//get everything under flag
					if(has_flags != false){
						
						//get the flags
						FlagsArrayType flaggedArrayType = amt.getTypes().getFlags();
							
							//get all the flags
							FlagsType [] flags = flaggedArrayType.getFlag();
							
							//loop through each flag
							for(int i = 0; i < flags.length; i++){
								
								String flagId = flags[i].getId().toString(); //get id
								String flagTag = flags[i].getTag().toString(); //get tag 
								String flagText = flags[i].getTextDesc(); //get text dec
								
								//if default is not true, then set it to false
								boolean flagDef;
								try{
									flagDef = flags[i].get_default(); // get default
								}catch(NullPointerException e){
									flagDef = false;
								}

								//save all the information into flag
								Flag thisflag = new Flag();
								thisflag.setId(flagId);
								thisflag.setTag(flagTag);
								thisflag.setText(flagText);
								thisflag.setDefaultValue(flagDef);
								
								//also add into flag set
								flag_set.add(thisflag);
								
								//add this flag into one of the group in the group_set
								if(!addIntoGroup(thisflag)){
		                        	ArrayList<Flag> updated = unknownGroup.getFlag_set();
		                        	//add this flag into this group flag set
		                        	updated.add(thisflag);
		                        	//add this flag set into this group
		                        	unknownGroup.setFlag_set( updated);	
		        					unknownGroup.setUseful(true);
		                        }
							}
					}//end of flag if
					
					//get everything under tagged
					if(has_tagged != false ){
						
						//get all taggedParam 
						ParamsArrayType taggedArrayType = amt.getTypes().getTaggedParams();	
						
							
							//get all tagged params
							ParamsType[] tagParams = taggedArrayType.getParam();
							
							//get separator and set to ' ' if it's null
							separator = taggedArrayType.getSeparator();
							if(separator == null)
								separator = " ";
							
							//loop through tagged params
							for (int i = 0; i < tagParams.length; i++) {
								
								String tagParamId = tagParams[i].getId().toString();//get id
								String tagParamTag = tagParams[i].getTag().toString();//get tag
								String tagParamPType = tagParams[i].getParamType().toString();//get param type
								String tagParamDec = tagParams[i].getTextDesc();//get text desc

								
								boolean tagParamReq;
								try{
									tagParamReq = tagParams[i].getRequired();// get required
								}catch(NullPointerException e){
									tagParamReq = false;
								}  
								
								String[] tagParamValues;
								try{
									tagParamValues = tagParams[i].getValue();//get all values
								}catch(NullPointerException e){
									tagParamValues = new String[]{};
								}
					
								String tagParamDef;
								try{
								tagParamDef = tagParams[i].get_default().toString();//get default
								}catch(NullPointerException e){
									tagParamDef = "no default";
								}
																
								String tagParamIoType;
								try{
								tagParamIoType = tagParams[i].getIoType().toString();//getIOType
								}catch(NullPointerException e){
									tagParamIoType = "no IOType";
								}	
								
								//save info into this tag var
								taggedParams thistagged = new taggedParams();
								thistagged.setId(tagParamId);
								thistagged.setTag(tagParamTag);
								thistagged.setPtype(tagParamPType);
								thistagged.setText(tagParamDec);
								thistagged.setRequired(tagParamReq);
								thistagged.setValues(tagParamValues);
								thistagged.setDefalut(tagParamDef);
								thistagged.setIotype(tagParamIoType);
								tagged_set.add(thistagged);
								
								//add this tagged into one of the group in the group_set
								if(!addIntoGroup(thistagged)){
		                        	ArrayList<taggedParams> updated = unknownGroup.getTagged_set();
		                        	//add this tagged into this group tagged set
		                        	updated.add(thistagged);
		                        	//add this tagged set into this group
		                        	unknownGroup.setTagged_set( updated);
		        					unknownGroup.setUseful(true);
		                        }
							}
					}//end of tag if
					
					if(has_untagged != false){
						
						//get all untaggedParam 
						ParamsArrayType untaggedArrayType = amt.getTypes().getUntaggedParams();	
							
							//get all untagged params
							ParamsType[] untagParams = untaggedArrayType.getParam();
							
							//loop through untagged params
							for (int i = 0; i < untagParams.length; i++) {
								String untagParamId = untagParams[i].getId().toString();//get id
								String untagParamPType = untagParams[i].getParamType().toString();//get param type
								String untagParamDec = untagParams[i].getTextDesc().toString();// get text description
							
							
								boolean untagParamrequired;
								try{
									untagParamrequired = untagParams[i].getRequired();// get required
								}catch(NullPointerException e){
									untagParamrequired = false;
								}
								
								String[] untagParamValues;
								try{
									untagParamValues = untagParams[i].getValue();//get all values
								}catch(NullPointerException e){
									untagParamValues = new String[]{};
								}
					
								String untagParamDef;
								try{
									untagParamDef = untagParams[i].get_default().toString();//get default
								}catch(NullPointerException e){
									untagParamDef = "no default";
								}
																
								String untagParamIoType;
								try{
									untagParamIoType = untagParams[i].getIoType().toString();//getIOType
								}catch(NullPointerException e){
									untagParamIoType = "no IOType";
								}
								
								//save info into this tag var
								untaggedParams thisuntagged = new untaggedParams();
								thisuntagged.setId(untagParamId);
								thisuntagged.setPtype(untagParamPType);
								thisuntagged.setText(untagParamDec);
								thisuntagged.setRequired(untagParamrequired);
								thisuntagged.setValues(untagParamValues);
								thisuntagged.setDefalut(untagParamDef);
								thisuntagged.setIotype(untagParamIoType);
								thisuntagged.setPosition(i);
								untagged_set.add(thisuntagged);
							
								//add this tagged into one of the group in the group_set
								if(!addIntoGroup(thisuntagged)){
		                        	ArrayList<untaggedParams> updated = unknownGroup.getUntagged_set();
		                        	//add this untagged into this group untagged set
		                        	updated.add(thisuntagged);
		                        	//add this untagged set into this group
		                        	unknownGroup.setUntagged_set( updated);
		        					unknownGroup.setUseful(true);
								}
							}							
					}//end of untag if
					
					// make this group in case of metadata dont have groups
					unknownGroup.setName("unknowgroup");
					unknownGroup.setIds(new ArrayList<String>());
					unknownGroup.setText("Ungrouped input fields");
					unknownGroup.setRequired(false);
					unknownGroup.setExclusive(false);
					group_set.add(unknownGroup);
					
				}//end of else
			} catch (Throwable e) {
				e.printStackTrace();
			}
	}

	public ArrayList<Flag> getFlag_set() {
		return flag_set;
	}

	public void setFlag_set(ArrayList<Flag> flag_set) {
		this.flag_set = flag_set;
	}

	public String getAppname() {
		return appname;
	}

	public void setAppname(String appname) {
		this.appname = appname;
	}

	public String getUsage() {
		return usage;
	}

	public void setUsage(String usage) {
		this.usage = usage;
	}

	public String[] getInfos() {
		return infos;
	}

	public void setInfos(String[] infos) {
		this.infos = infos;
	}

	public ArrayList<taggedParams> getTagged_set() {
		return tagged_set;
	}

	public void setTagged_set(ArrayList<taggedParams> tagged_set) {
		this.tagged_set = tagged_set;
	}

	public String getSeparator() {
		return separator;
	}

	public void setSeparator(String separator) {
		this.separator = separator;
	}

	public ArrayList<untaggedParams> getUntagged_set() {
		return untagged_set;
	}

	public void setUntagged_set(ArrayList<untaggedParams> untagged_set) {
		this.untagged_set = untagged_set;
	}

	public ArrayList<Group> getGroup_set() {
		return group_set;
	}

	public void setGroup_set(ArrayList<Group> group_set) {
		this.group_set = group_set;
	}

	public Set<String> getFile_set() {
		return file_set;
	}

	public void setFile_set(Set<String> file_set) {
		this.file_set = file_set;
	}

	//add flag, tagged, untagged into their group
	private boolean addIntoGroup(Object newParam){
		for(int i = 0; i < group_set.size(); i++){
				//get ids in this group
                ArrayList<String> ids = group_set.get(i).getIds();
                //flag type
                if(newParam.getClass().equals(Flag.class)){
                	//loop through ids
                    for(int j =0; j < ids.size(); j++){
                        String id = ((Flag)newParam).getId();
                        
                        //if id is in this group
                        if(id.equals( ids.get(j) ) ){
                        	
                        	ArrayList<Flag> updated = group_set.get(i).getFlag_set();
                        	//add this flag into this group flag set
                        	updated.add((Flag)newParam);
                        	//add this flag set into this group
                        	group_set.get(i).setFlag_set( updated);
                        	
                        	//return true when success add into one of the group.
                        	return true;
                        }
                    }
                }
                //taggedParams type
                else if(newParam.getClass().equals(taggedParams.class)){
                	//loop through ids
                    for(int j =0; j < ids.size(); j++){
                        String id = ((taggedParams)newParam).getId();
                        
                        //if id is in this group
                        if(id.equals( ids.get(j) ) ){
                        	
                        	ArrayList<taggedParams> updated = group_set.get(i).getTagged_set();
                        	//add this taggedParams into this group taggedParams set
                        	updated.add((taggedParams)newParam);
                        	//add this taggedParams set into this group
                        	group_set.get(i).setTagged_set( updated);
                        	
                        	//return true when success add into one of the group.
                        	return true;
                        }
                    }
                	
                }
                //untaggedParams type
                else if(newParam.getClass().equals(untaggedParams.class)){
                	//loop through ids
                    for(int j =0; j < ids.size(); j++){
                        String id = ((untaggedParams)newParam).getId();
                        
                        //if id is in this group
                        if(id.equals( ids.get(j) ) ){
                        	
                        	ArrayList<untaggedParams> updated = group_set.get(i).getUntagged_set();
                        	//add this untaggedParams into this group untaggedParams set
                        	updated.add((untaggedParams)newParam);
                        	//add this untaggedParams set into this group
                        	group_set.get(i).setUntagged_set( updated);
                        	
                        	//return true when success add into one of the group.
                        	return true;
                        	
                        }
                    }
               }
                
		}//end of for:i
		
    	//return false when unsuccess add into one of the group.
		return false;
	}

	public boolean isBasic() {
		return basic;
	}

	public void setBasic(boolean basic) {
		this.basic = basic;
	}
	
	
	
}



